package fr.umlv.ig.metroView.map;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import fr.umlv.ig.model.Itinerary;
import fr.umlv.ig.model.Line;
import fr.umlv.ig.model.MetroModel;
import fr.umlv.ig.model.Station;


/**
 * this class is use for initialize a map of case and get the nearest topleftcorner point
 * 
 * @author William Choy
 *
 */
public class MetroMapCases {

	
	/**
	 * this method is use to initialize the key of mapCases, the mapCases is a map with the topleftConer of a case in key
	 * and in value we have a list of station contained in this case
	 * @param mapCases is a map with Point for key and List<Station> for Value
	 * @param caseWidth width of the case
	 * @param caseHeight height of the case
	 */
	public static void initKeys(Map<Point, List<Station>> mapCases, int caseWidth, int caseHeight) {
		for(int i=0; i<10; i++) {
			for(int j=0; j<10; j++){
				Point p = new Point(i*caseWidth,j*caseHeight);
				mapCases.put(p, new ArrayList<Station>());
			}
		}	
	}
	
	/**
	 * initialize the value of mapCases
	 * @param metroModel model for collecting data
	 * @param mapCases map to init
	 * @param stationSize size of station
	 * @param caseWidth width of the case
	 * @param caseHeight height of the case
	 */
	public static void initValues(MetroModel metroModel, Map<Point, List<Station>> mapCases
			, int stationSize, int caseWidth, int caseHeight) {
		int numberOfLine = metroModel.getCountLine();
		for(int i = 0; i<numberOfLine; i++) {
			Line line = metroModel.getLine(i);
			int numberOfItinerary = metroModel.getCountItinerary(line);
			Set<String> stationsDraw = new HashSet<String>();
			for(int j=0; j < numberOfItinerary; j++) {
				Itinerary itinerary = metroModel.getItinerary(line, j);
				nextStation(metroModel, mapCases, metroModel.getStart(itinerary), stationsDraw, stationSize, caseWidth, caseHeight);
			}
		}
	}
	
	/**
	 * this method is use by initValues for reach all stations and put it in mapCase
	 * @param metroModel model for collecting data
	 * @param mapCases map to init
	 * @param station to put in the map
	 * @param stationsDraw
	 * @param stationSize size of station
	 * @param caseWidth width of the case
	 * @param caseHeight height of the case
	 */
	private static void nextStation(MetroModel metroModel, Map<Point, List<Station>> mapCases, Station station, Set<String> stationsDraw,
			int stationSize, int caseWidth, int caseHeight) {
		stationsDraw.add(station.getName());
		int stationHalfSize = stationSize/2;
		
		Map<Station,Station> mapNextStations = metroModel.getMapNextStations(station);
		for(Entry<Station, Station> entryStation : mapNextStations.entrySet()) {
			Station nextStation = entryStation.getValue();
			if(!stationsDraw.contains(nextStation.getName())) {
				nextStation(metroModel, mapCases, nextStation, stationsDraw, stationSize, caseWidth, caseHeight);
			}	
		}	
		int x = metroModel.getX(station) - stationHalfSize;
		int y = metroModel.getY(station) - stationHalfSize;
		Rectangle rectStation = new Rectangle(x , y, stationSize , stationSize);
		
		Rectangle rectCase = new Rectangle(new Dimension(caseWidth, caseHeight));
		for(Point p : mapCases.keySet()) {
			rectCase.setLocation(p);
			if(rectCase.intersects(rectStation)) {
				List<Station> listCasesStations = mapCases.get(p);
				listCasesStations.add(station);
			}
		}
	}
	
	/**
	 * this method is use for get the nearest point of a topleftcorner point
	 * it's return the topleftcorner point
	 */
	public static Point getCase(Point p, int caseWidth, int caseHeight) {
		Point newPoint = new Point();
		newPoint.x = p.x - (p.x%caseWidth);
		newPoint.y = p.y - (p.y%caseHeight);
		return newPoint;
	}

	/**
	 * this method is use for get the nearest point of a topleftcorner point
	 * it's return the topleftcorner point
	 */
	public static Point getCase(int x, int y, int caseWidth, int caseHeight) {
		Point newPoint = new Point();
		newPoint.x = x - (x%caseWidth);
		newPoint.y = y - (y%caseHeight);
		return newPoint;
	}
}
